import random
import numpy as nm


# 包装成一个函数，叫adjacent_random_augment,输入输出都是类似liked_graph那样的邻接矩阵
# 注意函数里自带两个变量A和B，是(0, 1)的参数，先定义好，A=0.4，B=0.5
# 函数的输入是liked_graph
# 函数的任务是统计liked_graph里零元素的数量，在liked_graph里选比例为A的零元素，具体数量向下取整
# 然后把这些元素的值从0变成B，得到的结果存在一个新矩阵
# 输出得到的新矩阵变量，叫random_augmented_like_graph
def random_graph_augment(liked_graph, sample_proportion=0.1, augment_value=1):
    # 复制一份基础的交互矩阵
    augmented_liked_graph = liked_graph.copy()

    # 找出0元素的id
    zero_index = nm.argwhere(augmented_liked_graph == 0)
    num_of_zero = len(zero_index)

    # 根据预定比例确定随机增强的元素个数
    sample_num = int(num_of_zero * sample_proportion)
    # 以及随机增强元素的id
    random_index = random.sample(zero_index.tolist(), sample_num)

    # 对指定0元素进行增强赋值
    for index in random_index:
        augmented_liked_graph[index[0], index[1]] = augment_value

    return augmented_liked_graph


# 基于随机增强矩阵计算资源分配矩阵
def random_weights_compute(num_of_item, num_of_user, random_augment_liked_graph):
    # 统计用户和项目的度，即用户看过的项目，和项目被看过的用户数量
    ra_item_degree_vector = nm.zeros([num_of_item])
    ra_user_degree_vector = nm.zeros([num_of_user])

    # 求每个项目的度，存在对应向量里
    for item_id in range(num_of_item):
        ra_item_degree_vector[item_id] = nm.count_nonzero(random_augment_liked_graph[item_id, :])
    # 求每个用户的度，存在对应向量里
    for user_id in range(num_of_user):
        ra_user_degree_vector[user_id] = nm.count_nonzero(random_augment_liked_graph[:, user_id])

    # 计算每个用户未交互项目的度
    ra_user_interact_item_num_total = nm.ones(num_of_user)
    ra_user_interact_item_num_total *= num_of_item
    ra_user_not_interact_item_num = ra_user_interact_item_num_total - ra_user_degree_vector

    # 为防止之后的除法出现0，手动将0值改为极大值
    for item_id in range(num_of_item):
        if ra_item_degree_vector[item_id] == 0.0:
            ra_item_degree_vector[item_id] = 99999
    for user_id in range(num_of_user):
        if ra_user_degree_vector[user_id] == 0.0:
            ra_user_degree_vector[user_id] = 99999

    # 求资源配额矩阵
    ra_weights = nm.zeros([num_of_item, num_of_item])
    # 转换为矩阵乘法和向量除法
    # 设定若干中间值
    ra_liked_graph_t = random_augment_liked_graph.transpose()
    ra_temp = nm.zeros([num_of_user, num_of_item])

    for i in range(num_of_item):
        ra_temp[:, i] = ra_liked_graph_t[:, i] / ra_user_degree_vector
    ra_temp = nm.dot(random_augment_liked_graph, ra_temp)
    for i in range(num_of_item):
        ra_weights[i, :] = ra_temp[i, :] / ra_item_degree_vector

    return ra_weights
